package com.tomz.xatomic.xa;

import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.util.Assert;

import java.lang.reflect.Constructor;
import java.util.Map;

/**
 * 将所有mapper映射接口类添加到每个sqlSession的Configuration中，
 * 默认的MapperFactoryBean无法实现将Mapper映射到所有数据源
 * @author ZHUFEIFEI
 */
public class XaDynamicMapperFactoryBean<T> extends MapperFactoryBean<T> {

    public XaDynamicMapperFactoryBean() {
    }

    /**
     * 必须继承父类，否则实例化Mapper时候，该factory只会被扫描到一个无参构造，最终mapperInterface参数无法设置，
     * 导致Mapper类无法实例化创建
     * {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory}
     * {@link org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor(String, RootBeanDefinition, Constructor[], Object[])}
     * @param mapperInterface
     */
    public XaDynamicMapperFactoryBean(Class<T> mapperInterface) {
        super(mapperInterface);
    }

    @Override
    protected void checkDaoConfig() {
        super.checkDaoConfig();

        SqlSession session = getSqlSession();

        Assert.isTrue(session.getClass().isAssignableFrom(XaDynamicSqlSessionTemplate.class), "Not support SqlSession Type : " + getSqlSession().getClass());

        XaDynamicSqlSessionTemplate xaSession = XaDynamicSqlSessionTemplate.class.cast(session);

        for (Map.Entry<String, SqlSessionTemplate> kv : xaSession.sqlSessionTemplates().entrySet()) {
            Configuration configuration = kv.getValue().getConfiguration();
            if (super.isAddToConfig() && !configuration.hasMapper(super.getMapperInterface())) {
                try {
                    configuration.addMapper(super.getMapperInterface());
                } catch (Exception e) {
                    logger.error("Error while adding the mapper '" + super.getMapperInterface() + "' to configuration ", e);
                    throw new IllegalArgumentException(e);
                } finally {
                    ErrorContext.instance().reset();
                }
            }
        }
    }
}
